// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
/* Copyright (C) 2016-2018, LomboTech Co.Ltd.
 * Author: lomboswer <lomboswer@lombotech.com>
 *
 * VISS-VILD driver code for LomboTech
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/bug.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/list.h>
#include <linux/mfd/syscon.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
#include <linux/delay.h>
#include <mach/common.h>

/* #define ENABLE_TRACE */
#include <mach/debug.h>

#include "viss.h"
#include "media-dev.h"
#include "viss-vild.h"
#include "csp.h"

struct viss_vild *g_vild;

static irqreturn_t vild_irq_handler(int irq, void *priv)
{
	PRT_TRACE_BEGIN("\n");


	PRT_TRACE_END("\n");

	return IRQ_HANDLED;
}
static int vild_subdev_registered(struct v4l2_subdev *sd)
{
	struct viss_vild *vild = v4l2_get_subdevdata(sd);
	struct video_device *vfd = &vild->vfd;
	int ret;

	PRT_TRACE_BEGIN("\n");

	vfd->v4l2_dev = sd->v4l2_dev;


	vild->vd_pad.flags = MEDIA_PAD_FL_SINK;
	ret = media_entity_pads_init(&vfd->entity, 1, &vild->vd_pad);
	if (ret < 0)
		return ret;

	video_set_drvdata(vfd, vild);
	vild->pipeline_ops = v4l2_get_subdev_hostdata(sd);

	PRT_INFO("Registered vild\n");
	PRT_TRACE_END("\n");
	return 0;

}

static void vild_subdev_unregistered(struct v4l2_subdev *sd)
{
}

static const struct v4l2_subdev_internal_ops vild_subdev_internal_ops = {
	.registered = vild_subdev_registered,
	.unregistered = vild_subdev_unregistered,
};

static int vild_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct viss_vild *vild;
	struct resource *res;
	int ret;

	PRT_TRACE_BEGIN("\n");

	if (dev->of_node == NULL) {
		PRT_DBG("no device data specified\n");
		return -ENOENT;
	}

	vild = devm_kzalloc(dev, sizeof(*vild), GFP_KERNEL);
	if (!vild) {
		PRT_ERR("create struct vild failed!\n");
		return -ENOMEM;
	}

	g_vild = vild;

	vild->pdev = pdev;

	spin_lock_init(&vild->slock);
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	vild->regs = devm_ioremap_resource(dev, res);
	if (IS_ERR(vild->regs))
		return PTR_ERR(vild->regs);

	csp_vild_set_register_base(vild->regs);

	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (res == NULL) {
		dev_err(dev, "Failed to get IRQ resource\n");
		return -ENXIO;
	}
	csp_vild_set_register_base(vild->regs);

	ret = devm_request_irq(dev, res->start, vild_irq_handler,
				       0, dev_name(dev), vild);
	if (ret) {
		dev_err(dev, "Failed to install irq (%d)\n", ret);
		return -ENXIO;
	}

	platform_set_drvdata(pdev, vild);
	pm_runtime_enable(dev);

	PRT_INFO("probe end!\n");

	PRT_TRACE_END("\n");

	return 0;
}

static int vild_remove(struct platform_device *pdev)
{
	PRT_INFO("TODO...\n");
	return 0;
}

#ifdef CONFIG_PM
static int vild_runtime_resume(struct device *dev)
{
	return 0;
}

static int vild_runtime_suspend(struct device *dev)
{
	return 0;
}
#endif

#ifdef CONFIG_PM_SLEEP
static int vild_resume(struct device *dev)
{
	return 0;
}

static int vild_suspend(struct device *dev)
{
	return 0;
}
#endif /* CONFIG_PM_SLEEP */

static const struct dev_pm_ops vild_pm_ops = {

#ifdef CONFIG_PM_SLEEP
	SET_SYSTEM_SLEEP_PM_OPS(vild_suspend, vild_resume)
#endif

#ifdef CONFIG_PM
	SET_RUNTIME_PM_OPS(vild_runtime_suspend, vild_runtime_resume, NULL)
#endif

};
#define DRIVER_NAME "lombo,viss-vild"

static const struct of_device_id vild_of_match[] = {
	{
		.compatible = DRIVER_NAME,
	},
};

static struct platform_driver vild_driver = {
	.probe		= vild_probe,
	.remove		= vild_remove,
	.driver = {
		.of_match_table = vild_of_match,
		.name		= VILD_DRV_NAME,
		.owner		= THIS_MODULE,
		.pm		= &vild_pm_ops,
	}
};
module_platform_driver(vild_driver);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" VILD_DRV_NAME);
